﻿
#define SPADAS_DEPRECATED_HIDE
#include "NextMJpegDecoderCPU.h"
#include "ffmpegdl.h"

namespace videonext
{
	class MJpegDecoderCPUVars : public Vars
	{
	public:
		Pointer decoder;
		Size2D frameSize;
	};
}

using namespace videonext;

MJpegDecoderCPU::MJpegDecoderCPU() : Object<MJpegDecoderCPUVars>(new MJpegDecoderCPUVars, TRUE)
{
	vars->decoder = 0;
}
bool MJpegDecoderCPU::open(Size2D frameSize)
{
	close();

	Pointer targetCodec = avcodec_find_decoder_by_name("mjpeg");
	if (targetCodec == 0) return false;

	Pointer decoderTmp = avcodec_alloc_context3(targetCodec);
	if (decoderTmp == 0) return false;

	int resultOpenCodec = avcodec_open2(decoderTmp, targetCodec, NULL);
	if (resultOpenCodec < 0)
	{
		avcodec_free_context(&decoderTmp);
		return false;
	}

	vars->decoder = decoderTmp;
	vars->frameSize = frameSize;

	return true;
}
void MJpegDecoderCPU::close()
{
	if (vars->decoder) avcodec_free_context(&vars->decoder);
	vars->decoder = 0;
}
CompatibleImage MJpegDecoderCPU::decode(Binary packetData)
{
	if (!vars->decoder) return CompatibleImage();

	Pointer packet = NULL;
	if (getFFMPEGLibraryVersion() >= 3)
	{
		packet = av_packet_alloc();
	}
	else
	{
		packet = av_mallocz_av_packet();
	}
	av_new_packet(packet, packetData.size());
	utility::memoryCopy(packetData.data(), av_packet_get_data(packet), packetData.size());

	av_packet_set_pts(packet, 0);
	av_packet_set_dts(packet, 0);

	Pointer frame = av_frame_alloc();
	if (!frame) return CompatibleImage();

	if (getFFMPEGLibraryVersion() >= 3)
	{
		Int resultSendPacket = avcodec_send_packet(vars->decoder, packet);
		Bool sendOK = resultSendPacket >= 0;

		av_packet_unref(packet);
		av_packet_free(&packet);

		if (!sendOK)
		{
			av_frame_free(&frame);
			return CompatibleImage();
		}

		Int resultReceiveFrame = avcodec_receive_frame(vars->decoder, frame);
		if (resultReceiveFrame < 0)
		{
			close();
			av_frame_free(&frame);
			return CompatibleImage();
		}
	}
	else
	{
		Int gotFrame = 0;
		Int resultDecode = avcodec_decode_video2(vars->decoder, frame, &gotFrame, packet);

		av_packet_unref(packet);
		av_free_packet(packet);
		packet = NULL;

		if (resultDecode < 0 || !gotFrame)
		{
			av_frame_free(&frame);
			return CompatibleImage();
		}
	}

	if (vars->frameSize.width > 0 && av_frame_get_width(frame) > (Int)vars->frameSize.width) av_frame_set_width(frame, vars->frameSize.width);
	if (vars->frameSize.height > 0 && av_frame_get_height(frame) > (Int)vars->frameSize.height) av_frame_set_height(frame, vars->frameSize.height);

	return CompatibleImage(frame, TRUE);
}
